// (C) Copyright 2012 Kystar. All rights reserved.

`timescale 1ns/100ps
`default_nettype none

module net_idle_pkg
(
    input  wire          I_sclk,
    input  wire          I_rst_n,
    // 
    input  wire          I_sent_pkg_start,
    output reg           O_send_pkg_ok,
    output reg           O_sending_pkg,
    // net arbitration
    output reg           O_req_net,
    input  wire          I_ack_net,
    // output
    output reg           O_net_out_en,
    output reg  [ 7: 0]  O_net_out_data,
    // ram interface - 2048 Byte
    output reg  [ 10: 0] O_pkg_ram_rdaddr,
    input  wire [ 7: 0]  I_pkg_ram_rddata,
    // registers
    input  wire [ 11: 0] I_reg_pkg_byte_num
);

/******************************************************************************
                                <localparams>
******************************************************************************/
localparam
    NET_HEAD_BYTES = 8;

localparam // state
    IDLE = 0,
    NET_REQ = 1,
    SEND_NET_HEAD = 1<<1,
	SEND_IDLE_PKG_HEAD = 1<<2,
    SEND_IDLE_PKG_DATA = 1<<3;

/******************************************************************************
                              <internal signals>
******************************************************************************/
reg  [ 3: 0] state;
reg  [ 3: 0] next_state;
reg  [ 10: 0] data_cnt;
reg  [ 2: 0] head_cnt;

/******************************************************************************
                                <module body>
******************************************************************************/

// state machine : state
always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        state <= IDLE;
    else if (I_sent_pkg_start)
        state <= NET_REQ;
    else
        state <= next_state;

always @(*)
    case (state)
        IDLE:
            next_state = IDLE;
        NET_REQ:
            if (I_ack_net)
                next_state = SEND_NET_HEAD;
            else
                next_state = NET_REQ;
        SEND_NET_HEAD:
            if (head_cnt == NET_HEAD_BYTES - 1)
                next_state = SEND_IDLE_PKG_HEAD;
            else
                next_state = SEND_NET_HEAD;
		SEND_IDLE_PKG_HEAD:
		    if (data_cnt == 'd55)  // head
			    next_state = SEND_IDLE_PKG_DATA;
			else
			    next_state = SEND_IDLE_PKG_HEAD;
        SEND_IDLE_PKG_DATA:
            if (data_cnt == I_reg_pkg_byte_num - 1'b1)
                next_state = IDLE;
            else
                next_state = SEND_IDLE_PKG_DATA;
        default:
            next_state = IDLE;
    endcase

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_send_pkg_ok <= 1'b0;
    else
        O_send_pkg_ok <= state == SEND_IDLE_PKG_DATA && (data_cnt == I_reg_pkg_byte_num - 1'b1);

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_sending_pkg <= 1'b0;
    else
        O_sending_pkg <= state != IDLE;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_req_net <= 1'b0;
    else if (state == IDLE)
        O_req_net <= 1'b0;
    else
        O_req_net <= 1'b1;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        head_cnt <= 'd0;
    else if (state == SEND_NET_HEAD)
        head_cnt <= head_cnt + 1;
    else
        head_cnt <= 'd0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_net_out_en <= 1'b0;
    else if (state == SEND_NET_HEAD || state == SEND_IDLE_PKG_HEAD || state == SEND_IDLE_PKG_DATA)
        O_net_out_en <= 1'b1;
    else
        O_net_out_en <= 1'b0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_net_out_data <= 8'h0;
    else if (state == SEND_NET_HEAD)
        begin
        if (head_cnt == NET_HEAD_BYTES - 1'b1)
            O_net_out_data <= 8'hD5;
        else
            O_net_out_data <= 8'h55;
        end
    else if (state == SEND_IDLE_PKG_HEAD)
        O_net_out_data <= I_pkg_ram_rddata;
    else
        O_net_out_data <= 'd0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_pkg_ram_rdaddr <= 'd0;
    else if (I_sent_pkg_start)
        O_pkg_ram_rdaddr <= 'd0;
    else if (state == SEND_NET_HEAD && head_cnt == NET_HEAD_BYTES - 'd2)
        O_pkg_ram_rdaddr <= 'd1;
    else if (state == SEND_NET_HEAD && head_cnt == NET_HEAD_BYTES - 1'b1)
        O_pkg_ram_rdaddr <= 'd2;
    else if (state == SEND_IDLE_PKG_HEAD)
        O_pkg_ram_rdaddr <= O_pkg_ram_rdaddr + 1'b1;
    else
        O_pkg_ram_rdaddr <= 'd0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        data_cnt <= 'd0;
    else if ((state == SEND_IDLE_PKG_DATA) | (state == SEND_IDLE_PKG_HEAD))
        data_cnt <= data_cnt + 1;
    else
        data_cnt <= 'd0;

endmodule
`default_nettype wire

